﻿#region Includes
using System;
using System.Collections.Generic;
using OpenTK;
using GingerGL;
using GingerGL.IO;
using GingerGL.Math;
using GingerGL.Drawing;
using GingerGL.Graphics;
#endregion

namespace GingerGL.Drawing.MD3
{
    //------------------------------------------------------------//
    /// <summary>
    /// Quake MD3 Entity
    /// </summary>
    public class Model
    {
        //--------------------------------------------------------//
        #region Variables
        /// <summary>
        /// Name of MD3
        /// </summary>
        public String Name { get; private set; }
        /// <summary>
        /// Gender of MD3
        /// </summary>
        public Gender Gender { get; private set; }
        /// <summary>
        /// Offset for the Head
        /// </summary>
        public Vector3 HeadOffset { get; private set; }
        /// <summary>
        /// Footsteps Sound
        /// </summary>
        public string Footsetps { get; private set; }
        /// <summary>
        /// MD3 Components
        /// </summary>
        public Component[] Components { get; private set; }
        /// <summary>
        /// MD3 Animation Sequences
        /// </summary>
        public Dictionary<string, List<AnimationSequence>> Sequences { get; private set; }
        /// <summary>
        /// MD3 Skins
        /// </summary>
        public List<Skin> Skins { get; private set; }
        /// <summary>
        /// LODs
        /// </summary>
        public LODLevel[] LODs { get; private set; }
        /// <summary>
        /// MD3 File System
        /// </summary>
        public IFileSystem FileSystem { get; private set; }
        /// <summary>
        /// Fast Look up for Active Animation Sequence
        /// </summary>
        protected Dictionary<string, Dictionary<string, AnimationSequence>> SequenceCache;
        /// <summary>
        /// Family Tree
        /// </summary>
        internal ConnectedComponent RootNode;
        #endregion
        //--------------------------------------------------------//
        #region Methods
        /// <summary>
        /// Gets and/or adds new skin to collection
        /// </summary>
        /// <param name="name">Name of Skin</param>
        /// <returns>New or Existing Skin</returns>
        public Skin GetSkin(string name)
        {
            foreach (Skin skin in Skins) { if (skin.Name == name) return skin; }
            Skin s = new Skin(name);
            Skins.Add(s);
            return s;
        }
        /// <summary>
        /// Gets TRUE if skin exists
        /// </summary>
        /// <param name="name">Skin Name</param>
        /// <returns>TRUE if skin exists</returns>
        public bool SkinExists(string name)
        {
            foreach (Skin skin in Skins) { if (skin.Name == name) return true; } return false;
        }
        /// <summary>
        /// Gets skin from Surface
        /// </summary>
        /// <returns>Skin</returns>
        public Skin SkinFromSurfs()
        {
            if (SkinExists("from_surfs"))  return GetSkin("from_surfs");
            Skin skin = new Skin("from_surfs");

            foreach (Component component in Components)
            {
                skin.Surfaces.Add(component.Name, new Dictionary<string, string>());

                Dictionary<string, string> comps = skin.Surfaces[component.Name];

                foreach (AnimatedMesh mesh in component.Meshes)
                {
                    if (mesh.ShaderFiles.Count > 0)
                        comps.Add(mesh.Name, mesh.ShaderFiles[0]);
                    else
                        comps.Add(mesh.Name, mesh.Name + ".tga");
                }
            }

            Skins.Add(skin);
            return skin;
        }
        /// <summary>
        /// Finds Component by name or returns a new component
        /// </summary>
        /// <param name="name">Component Name</param>
        /// <returns>New or Existing Component</returns>
        public Component FindComponent(string name)
        {
            foreach (Component comp in Components) { if (comp.FileName == name) return comp; }
            return null;
        }
        /// <summary>
        /// Finds Animation Sequence by name
        /// </summary>
        /// <param name="part">Component Part</param>
        /// <param name="name">Sequence Name</param>
        /// <returns>New or Existing Animation Sequence</returns>
        public AnimationSequence FindSequence(string part, string name)
        {
            if (SequenceCache == null)
            {
                SequenceCache = new Dictionary<string, Dictionary<string, AnimationSequence>>();
                foreach (KeyValuePair<string, List<AnimationSequence>> partSeq in Sequences)
                {
                    if (!SequenceCache.ContainsKey(partSeq.Key))
                        SequenceCache.Add(partSeq.Key, new Dictionary<string, AnimationSequence>());

                    Dictionary<string, AnimationSequence> seqs = SequenceCache[partSeq.Key];
                    foreach (AnimationSequence seq in partSeq.Value)
                    {
                        if (!seqs.ContainsKey(seq.Name))
                            seqs.Add(seq.Name, seq);
                    }
                }
            }

            if (!SequenceCache.ContainsKey(part))
                return new AnimationSequence();

            if (!SequenceCache[part].ContainsKey(name))
                return new AnimationSequence();

            return SequenceCache[part][name];
        }
        #endregion
        //--------------------------------------------------------//
        #region Constructors
        /// <summary>
        /// Initializes a new instance of object
        /// </summary>
        public Model(IFileSystem fs)
        {
            Name = String.Empty;
            Gender = Gender.Unknown;
            Components = new Component[5];
            Sequences = new Dictionary<string, List<AnimationSequence>>();
            Skins = new List<Skin>();
            FileSystem = fs;
        }
        #endregion
        //--------------------------------------------------------//
        #region Static Methods
        /// <summary>
        /// Load MD3 Pak
        /// </summary>
        static public Model[] Load(string path) { return Load(new ZipFileSystem(path)); }
        /// <summary>
        /// Load MD3
        /// </summary>
        static public Model[] Load(IFileSystem fs)
        {
            List<Model> models = new List<Model>();                                     //create model array
            List<string> unique_directories = new List<string>();                   //creating list of seperate players
            foreach (string dir in fs.GetDirectories("models/players", ""))         //using the md3 pak list, loads players
                if (!unique_directories.Contains(dir))                              //dblcheck
                    unique_directories.Add(dir);                                    //add dir
            foreach (string p in unique_directories.ToArray())                      //load each player
            {
                List<List<Component>> LODs = new List<List<Component>>();           //level of details
                Model model = new Model(fs);                                            //current model
                //loads components
                foreach (string f in fs.GetFiles(p))                                //get list of files
                {
                    
                    if (Path.GetExtension(f) == "md3")                              //if mesh?
                    {
                        Component c = LoadComponent(fs.Open(f), f);                 //load component
                        int LOD = 0;                                                //level of detail starts at 0
                        string componentName = string.Empty;                        //who you be?

                        if (f.Contains("_"))                                        //files are head_0.md3
                        {
                            string[] nugs = Path.GetFileNameWithoutExtension(f).Split("_".ToCharArray());
                            if (nugs.Length > 0 && char.IsNumber(nugs[nugs.Length - 1][0]))
                                LOD = int.Parse(nugs[nugs.Length - 1]);             //just want the head
                            componentName = nugs[0].ToLower();                      //lowercase please
                        }
                        else                                                        //no lod mesh sets
                            componentName = System.IO.Path.GetFileNameWithoutExtension(f).ToLower();

                        if (componentName == "lower") c.PartType = ComponentType.Legs;
                        else if (componentName == "upper") c.PartType = ComponentType.Torso;
                        else if (componentName == "head") c.PartType = ComponentType.Head;
                        else c.PartType = ComponentType.Other;

                        if (LOD > 0) continue;

                        if (LOD + 1 > LODs.Count)
                            for (int i = LODs.Count; i < LOD + 1; i++)
                                LODs.Add(new List<Component>());
                        LODs[LOD].Add(c);
                    }
                }
                //load configs
                foreach (string f in fs.GetFiles(p))
                    if (Path.GetExtension(f) == "cfg")
                        LoadConfig(fs, model, f);

                //load skins
                foreach (string f in fs.GetFiles(p))
                    if (Path.GetExtension(f) == "skin")
                        LoadSkins(fs, model, f);

                //config LOD's
                if (LODs.Count == 0) return null;
                model.Components = LODs[0].ToArray();
                model.LODs = new LODLevel[LODs.Count];
                int j = 0;
                foreach (List<Component> lod in LODs)
                {
                    model.LODs[j] = new LODLevel();
                    model.LODs[j].Componenets = lod.ToArray();
                    j++;
                }
                BuildCharacterTree(model);
                models.Add(model);
            }            
            return models.ToArray();
        }
        /// <summary>
        /// Loads MD3 Components
        /// </summary>
        static private Component LoadComponent(System.IO.Stream fs, string filename)
        {
            string MD3Ident = Utilities.ReadString(fs, 4);
            if (MD3Ident != "IDP3") throw new System.IO.FileLoadException("Incorrect file type.");  //check version            
            Int32 MD3Version = Utilities.ReadObject<Int32>(fs);                                     //version
            Component model = new Component(Utilities.ReadString(fs, 64));                          //name

            string trimfilename = System.IO.Path.GetFileNameWithoutExtension(filename);
            if (trimfilename.Contains("_")) trimfilename = trimfilename.Split("_".ToCharArray())[0];//format name
            model.FileName = Path.GetFileNameWithoutExtension(filename);                            //filename

            //counts
            UInt32 flags = Utilities.ReadObject<UInt32>(fs);                                        //flags
            Int32 frameCount = Utilities.ReadObject<Int32>(fs);                                     //frame count
            Int32 tagCount = Utilities.ReadObject<Int32>(fs);                                       //tag count
            Int32 surfaceCount = Utilities.ReadObject<Int32>(fs);                                   //surface count
            Int32 skinCount = Utilities.ReadObject<Int32>(fs);                                      //skin count
            //offsets
            Int32 frameOffset = Utilities.ReadObject<Int32>(fs);                                    //frame offset
            Int32 tagOffset = Utilities.ReadObject<Int32>(fs);                                      //tag offset
            Int32 surfaceOffset = Utilities.ReadObject<Int32>(fs);                                  //surface offset
            Int32 EOFOffset = Utilities.ReadObject<Int32>(fs);                                      //end of file

            if (!Utilities.StreamOffset(fs, frameOffset))                                           //move to frames
            { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

            List<MD3Frame> frames = new List<MD3Frame>();                                           //frame container
            for (int i = 0; i < frameCount; i++) frames.Add(Utilities.ReadObject<MD3Frame>(fs));    //read frames

            if (!Utilities.StreamOffset(fs, tagOffset))                                             //move to tags
            { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

            List<List<MD3Tag>> tagFrames = new List<List<MD3Tag>>();                                //tag container
            for (int i = 0; i < tagCount; i++)
                tagFrames.Add(new List<MD3Tag>());

            for (int f = 0; f < frameCount; f++)
                for (int i = 0; i < tagCount; i++)
                    tagFrames[i].Add(Utilities.ReadObject<MD3Tag>(fs));                             //read tags

            if (!Utilities.StreamOffset(fs, surfaceOffset))                                         //move to surfaces
            { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

            List<MD3Surface> Surfaces = new List<MD3Surface>();                                     //surfaces container
            for (int i = 0; i < surfaceCount; i++)                                                  //cycle thru the surfaces
            {
                MD3Surface surface = new MD3Surface();
                surface.Frames = new List<List<MD3Vertex>>();
                surface.Shaders = new List<MD3Shader>();
                surface.Triangles = new List<MD3Triangle>();
                surface.UVs = new List<MD3TexCoord>();
                //surface
                Int64 pos = fs.Position;                                                            //save base position

                surface.Header = Utilities.ReadObject<MD3SurfaceHeader>(fs);                        //read surface header

                if (!Utilities.StreamOffset(fs, (Int32)pos + surface.Header.ShaderOffset))          //move to shader offset
                { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

                for (int s = 0; s < surface.Header.ShaderCount; s++)                                //cycle thru the shaders
                    surface.Shaders.Add(Utilities.ReadObject<MD3Shader>(fs));                       //read shaders

                if (!Utilities.StreamOffset(fs, (Int32)pos + surface.Header.TriangleOffset))        //move to triangles
                { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

                for (int t = 0; t < surface.Header.TriangleCount; t++)                              //cycle thur triangle
                    surface.Triangles.Add(Utilities.ReadObject<MD3Triangle>(fs));                   //read triangle

                if (!Utilities.StreamOffset(fs, (Int32)pos + surface.Header.UVOffset))              //move to texcoords
                { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

                for (int u = 0; u < surface.Header.VertCount; u++)                                  //cycle thur coords
                    surface.UVs.Add(Utilities.ReadObject<MD3TexCoord>(fs));                         //read tex coords

                if (!Utilities.StreamOffset(fs, (Int32)pos + surface.Header.VertOffset))            //cycle thur verts
                { fs.Close(); throw new System.IO.FileLoadException("Offset is invalid."); }

                for (int f = 0; f < surface.Header.FrameCount; f++)                                 //cycle thru the frames
                {
                    List<MD3Vertex> frameVerts = new List<MD3Vertex>();                             //frame list
                    surface.Frames.Add(frameVerts);                                                 //set frame vets list

                    for (int v = 0; v < surface.Header.VertCount; v++)                              //cycle thru frame verts
                        frameVerts.Add(Utilities.ReadObject<MD3Vertex>(fs));                        //read verts
                }

                Surfaces.Add(surface);                                                              //add loaded surface
            }

            fs.Close();                                                                             //done with file

                                                                                                    //now that we have everthing we are going to
                                                                                                    //stuff into a MD3 Class, which basically
                                                                                                    //acts as the storage container for MD3 Models
            List<FrameInfo> modelFrames = new List<FrameInfo>();                                    //process frame info

            foreach (MD3Frame frame in frames)
            {
                FrameInfo info = new FrameInfo();
                info.Name = Utilities.FixString(frame.Name).ToLower();
                info.Max = new Vector3(frame.MaxBounds[0], frame.MaxBounds[1], frame.MaxBounds[2]);
                info.Min = new Vector3(frame.MinBounds[0], frame.MinBounds[1], frame.MinBounds[2]);
                info.Origin = new Vector3(frame.LocalOrigin[0], frame.LocalOrigin[1], frame.LocalOrigin[2]);
                info.Radius = frame.Radius;
                modelFrames.Add(info);
            }

            model.Frames = modelFrames.ToArray();

            List<Tag> modelTags = new List<Tag>();
            foreach (List<MD3Tag> tagList in tagFrames)
            {
                if (tagList.Count > 0)
                {
                    Tag tag = new Tag();
                    tag.Name = Utilities.FixString(tagList[0].Name).ToLower();
                    List<FrameMatrix> frameMats = new List<FrameMatrix>();
                    foreach (MD3Tag t in tagList)
                    {
                        FrameMatrix mat = new FrameMatrix();
                        mat.Matrix = new Matrix4(
                            t.R1[0], t.R1[1], t.R1[2], 0,
                            t.R2[0], t.R2[1], t.R2[2], 0,
                            t.R3[0], t.R3[1], t.R3[2], 0,
                            t.Origin[0], t.Origin[1], t.Origin[2], 1.0f);
                        mat.Inverse = Matrix4.Invert(mat.Matrix);
                        frameMats.Add(mat);
                    }
                    tag.Frames = frameMats.ToArray();
                    modelTags.Add(tag);
                }
            }
            model.Tags = modelTags.ToArray();

            List<AnimatedMesh> meshes = new List<AnimatedMesh>();
            foreach (MD3Surface surface in Surfaces)
            {
                AnimatedMesh mesh = new AnimatedMesh();
                mesh.Name = Utilities.FixString(surface.Header.Name).ToLower();

                #region Indices
                mesh.Triangles = new IndexBuffer();
                foreach (MD3Triangle triangle in surface.Triangles)
                {
                    int[] tri = triangle.Indexes;
                    Array.Reverse(tri);
                    mesh.Triangles.Write(tri);
                }
                mesh.Triangles.Commit();
                mesh.Triangles.Clear();
                #endregion

                #region Vertex
                List<Vector2> uvs = new List<Vector2>();
                foreach (MD3TexCoord coord in surface.UVs)
                    uvs.Add(new Vector2(coord.UV[0], coord.UV[1]));

                mesh.Frames = new List<Frame>();

                float factor = 1f / 64f;
                foreach (List<MD3Vertex> frameVerts in surface.Frames)
                {
                    Frame frame = new Frame();
                    int ndex = 0;
                    foreach (MD3Vertex v in frameVerts)
                    {
                        Vertex vert = new Vertex();
                        vert.Position = new Vector3(v.Coordinate[0] * factor, v.Coordinate[1] * factor, v.Coordinate[2] * factor);
                        Vector3 norm = new Vector3();
                        float lat = v.Normal[0] * (2f * (float)System.Math.PI) / 255f;
                        float lng = v.Normal[1] * (2f * (float)System.Math.PI) / 255f;
                        norm.X = (float)System.Math.Cos(lat) * (float)System.Math.Sin(lng);
                        norm.Y = (float)System.Math.Sin(lat) * (float)System.Math.Sin(lng);
                        norm.Z = (float)System.Math.Cos(lng);
                        norm.Normalize();
                        vert.Normal = norm;
                        vert.Texture = uvs[ndex++];
                        frame.Vertices.Write(vert);
                    }
                    frame.Vertices.Commit();
                    mesh.Frames.Add(frame);
                }
                #endregion

                #region Shaders
                mesh.ShaderFiles = new List<string>();
                foreach (MD3Shader shader in surface.Shaders)
                    mesh.ShaderFiles.Add(Utilities.FixString(shader.Name));
                #endregion

                meshes.Add(mesh);
            }
            model.Meshes = meshes.ToArray();

            return model;
        }
        /// <summary>
        /// Link Components together
        /// </summary>
        static private void LinkTreeChildren(Component parent, ConnectedComponent node, Dictionary<string, List<Component>> componentsWithTags)
        {
            foreach (Tag tag in node.Part.Tags)
            {
                if (tag.Name != "tag_floor")
                {
                    if (componentsWithTags.ContainsKey(tag.Name))
                    {
                        if (!node.Children.ContainsKey(tag)) node.Children.Add(tag, new List<ConnectedComponent>());
                        List<Component> linkedComponents = componentsWithTags[tag.Name];
                        foreach (Component c in linkedComponents)
                        {
                            if (c == node.Part || c == parent)
                                continue;
                            ConnectedComponent child = new ConnectedComponent(c);
                            node.Children[tag].Add(child);
                            LinkTreeChildren(node.Part, child, componentsWithTags);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Builds Character Tree
        /// </summary>
        static private void BuildCharacterTree(Model model)
        {
            Component root = null;
            Dictionary<string, List<Component>> componentsWithTags = new Dictionary<string, List<Component>>();

            foreach (Component part in model.Components)
            {
                if (part.FileName.EndsWith("lower")) root = part;
                foreach (Tag tag in part.Tags)
                {
                    if (!componentsWithTags.ContainsKey(tag.Name)) 
                        componentsWithTags.Add(tag.Name, new List<Component>());
                    componentsWithTags[tag.Name].Add(part);
                }
            }

            if (root == null) return;
            model.RootNode = new ConnectedComponent(root);
            LinkTreeChildren(null, model.RootNode, componentsWithTags);
        }
        /// <summary>
        /// Loads the MD3 Skins referances
        /// </summary>
        static private void LoadSkins(IFileSystem fs, Model model, string file)
        {
            string name = string.Empty;
            string component = string.Empty;

            string[] nugs = Path.GetFileNameWithoutExtension(file).Split("_".ToCharArray(), 2);
            if (nugs.Length > 0) component = nugs[0].ToLower();
            if (nugs.Length > 1) name = nugs[1].ToLower();

            Skin skin = model.GetSkin(name);
            System.IO.StreamReader sr = new System.IO.StreamReader(fs.Open(file));


            if (!skin.Surfaces.ContainsKey(component)) skin.Surfaces.Add(component, new Dictionary<string, string>());
            Dictionary<string, string> skinMeshes = skin.Surfaces[component];

            string line = sr.ReadLine();
            while (line != null)
            {
                if (line.Length > 0)
                {
                    nugs = line.Split(",".ToCharArray(), 2);
                    if (nugs.Length > 1)
                    {
                        if (skinMeshes.ContainsKey(nugs[0].ToLower()))
                            skinMeshes[nugs[0].ToLower()] = nugs[1].ToLower();
                        else
                            skinMeshes.Add(nugs[0].ToLower(), nugs[1].ToLower());
                    }
                }
                line = sr.ReadLine();
            }

            sr.Close();
        }
        /// <summary>
        /// Loads the MD3 Cfg File
        /// </summary>
        static private void LoadConfig(IFileSystem fs, Model model, string file)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(fs.Open(file));

            string line = sr.ReadLine();

            if (model.Sequences == null)
                model.Sequences = new Dictionary<string, List<AnimationSequence>>();

            int count = 0;

            int torsoStart = -1;
            int legsOffset = -1;

            while (line != null)
            {
                string[] nugs = line.Split(" \t".ToCharArray());
                if (nugs.Length > 0)
                {
                    string tag = nugs[0].ToLower();
                    if (tag == "sex" && nugs.Length > 1)
                    {
                        string gender = nugs[1].ToLower();
                        if (gender == "f")          model.Gender = Gender.Female;
                        else if (gender == "m")     model.Gender = Gender.Male;
                        else                        model.Gender = Gender.Unknown;
                    }
                    else if (tag == "headoffset" && nugs.Length > 3) model.HeadOffset = new Vector3(float.Parse(nugs[1]), float.Parse(nugs[2]), float.Parse(nugs[3]));
                    else if (tag == "footsteps" && nugs.Length > 1) model.Footsetps = nugs[1];
                    else if (tag.Length > 0 && char.IsNumber(tag[0]) && nugs.Length > 3)
                    {
                        AnimationSequence seq = new AnimationSequence();
                        seq.StartFrame = int.Parse(tag);
                        int length = int.Parse(nugs[1]);
                        seq.EndFrame = seq.StartFrame + length - 1;

                        int loop = int.Parse(nugs[2]);
                        if (loop == 0 || length == 1) seq.LoopPoint = seq.EndFrame;
                        else seq.LoopPoint = seq.EndFrame - (loop - 1);

                        float fps = float.Parse(nugs[3]);
                        if (fps > 0) seq.FPS = fps;

                        string name = string.Empty;
                        string part = "both";
                        if (nugs.Length > 6) name = nugs[6];

                        if (name != string.Empty)
                        {
                            string[] seqParts = name.Split("_".ToCharArray());
                            if (seqParts.Length > 1)
                            {
                                part = seqParts[0].ToLower();
                                name = seqParts[1].ToLower();
                            }
                            else
                                name = seqParts[0];
                        }
                        else
                        {
                            if (count < 6)
                            {
                                part = "both";
                                switch (count)
                                {
                                    case 0: name = "death1";    break;
                                    case 1: name = "dead1";     break;
                                    case 2: name = "death2";    break;
                                    case 3: name = "dead2";     break;
                                    case 4: name = "death3";    break;
                                    case 5: name = "dead3";     break;
                                }
                            }
                            else if (count < 13)
                            {
                                part = "torso";
                                switch (count)
                                {
                                    case 6: name = "gesture";   break;
                                    case 7: name = "attack";    break;
                                    case 8: name = "attak2";    break;
                                    case 9: name = "drop";      break;
                                    case 10: name = "raise";    break;
                                    case 11: name = "stand";    break;
                                    case 12: name = "stand2";   break;
                                }
                            }
                            else
                            {
                                part = "legs";
                                switch (count)
                                {
                                    case 13: name = "walkcr";   break;
                                    case 14: name = "walk";     break;
                                    case 15: name = "run";      break;
                                    case 16: name = "back";     break;
                                    case 17: name = "swim";     break;
                                    case 18: name = "jump";     break;
                                    case 19: name = "land";     break;
                                    case 20: name = "jumpb";    break;
                                    case 21: name = "landb";    break;
                                    case 22: name = "idle";     break;
                                    case 23: name = "idlecr";   break;
                                    case 24: name = "turn";     break;
                                }
                            }
                        }

                        if (torsoStart < 0 && part == "torso") torsoStart = seq.StartFrame;
                        if (legsOffset < 0 && part == "legs") legsOffset = seq.StartFrame - torsoStart;

                        if (part == "legs")
                        {
                            seq.StartFrame -= legsOffset;
                            seq.LoopPoint -= legsOffset;
                            seq.EndFrame -= legsOffset;
                        }

                        seq.Name = name;
                        if (part == "both")
                        {
                            if (!model.Sequences.ContainsKey("torso")) model.Sequences.Add("torso", new List<AnimationSequence>());
                            if (!model.Sequences.ContainsKey("legs")) model.Sequences.Add("legs", new List<AnimationSequence>());

                            model.Sequences["torso"].Add(seq);
                            model.Sequences["legs"].Add(seq);
                        }
                        else
                        {
                            if (!model.Sequences.ContainsKey(part)) model.Sequences.Add(part, new List<AnimationSequence>());
                            model.Sequences[part].Add(seq);
                        }
                        count++;
                    }
                }
                line = sr.ReadLine();
            }

            sr.Close();
        }
        #endregion
        //--------------------------------------------------------//
    }
    //------------------------------------------------------------//
}
